package com.gopay.bis.web.controller.expay;



import com.gopay.bis.domain.order.OrderInfo;
import com.gopay.common.Result;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.bank.NuccConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.domain.bank.nucc.expay.NuccExpayHeaderMessage;
import com.gopay.common.domain.bank.nucc.expay.common.NuccExpayCommonMsgbody;
import com.gopay.common.domain.bank.nucc.expay.common.NuccExpayCommonMsgbodySysrtninf;
import com.gopay.common.domain.bank.nucc.expay.common.NuccExpayCommonRes;
import com.gopay.common.domain.bank.nucc.expay.pay.end.NuccExpaymentEndRes;
import com.gopay.common.domain.bank.nucc.expay.refund.end.NuccExpayRefundEndRes;
import com.gopay.common.domain.bank.nucc.expay.rescind.res.NuccExpayRescindRes;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.ExPayInteractRemoteService;
import com.gopay.remote.bank.businesses.ExPayService;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Date;
import java.util.Map;


/** 
 * 网联异步通知（用于：用户主动解约，协议支付超时，退款超时）
 * @ClassName: NuccExpayServerRes 
 * @author w_jiqing 
 * @date 2017年8月8日 下午3:33:28  
 */ 

@Controller
@Scope("prototype")
public class NuccExpayServerRes extends ExpayRefundBankResBase{
    
    
    private static Log logger = LogFactory.getLog(NuccExpayServerRes.class);
    
    private final static String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
    
    @Resource(name = "nuccConfig")
    private Map<String, String> nuccConfig;
    
    @Resource(name ="nuccExPayService")
    private ExPayInteractRemoteService nuccExPayService;   
    
    @Resource(name="nuccExPayServiceClient")
    private ExPayService nuccExPayServiceClient;
  
    /**
     * 支付终态通知接口
     */
    @RequestMapping(value = "NuccPaymentServerRes")
    protected ModelAndView execute(HttpServletRequest request,HttpServletResponse response) {
        logger.error("--------------- NuccPaymentServerRes end notify  ---------------");
        return super.execute(request, response);
    }
    
    /**
     * 退款终态通知接口
     */
    @RequestMapping(value="NuccRefundServerRes")
    protected void executeRefund(HttpServletRequest request,HttpServletResponse response){
        logger.error("--------------- NuccRefundServerRes end notify  ---------------");
        super.executeRefund(request, response);
    }
    
    /** 
     * 解约接口，验签通过，修改签约状态
     * @param request
     * @param response
     * @return 
     * @author w_jiqing 
     */
    @ResponseBody
    @RequestMapping(value = "/cancel")
    protected void cancel(HttpServletRequest request, HttpServletResponse response){
        logger.error("--------------- NuccExpayServerRes cancel  ---------------");       
        NuccExpayRescindRes message = new NuccExpayRescindRes();
        String resMsg = null;
        ServletOutputStream out = null;
        PrintWriter pw  = null;
        try {            
            String paserXml = parseRequst(request);
            message = (NuccExpayRescindRes) this.cancelToBean(paserXml);
            Result result =  nuccExPayService.cancel(message);
            if(result.isSuccess()){
                NuccExpayCommonRes res = new  NuccExpayCommonRes();
                NuccExpayHeaderMessage header = new NuccExpayHeaderMessage();
                NuccExpayCommonMsgbody body = new NuccExpayCommonMsgbody();
                header.setSndDt(DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
                //报文类型代码
                header.setMsgTp(nuccConfig.get("NUCC.EXPAY.COMMON.MSGTP"));
                //发起方所属机构标示
                header.setIssrId(nuccConfig.get("GOPAY.ISSRID"));
                //报文方向  11-支付机构到平台
                header.setDrctn(nuccConfig.get("NUCC.EXPAY.DRCTN"));
                //签名证书序列号
                header.setSignSN(nuccConfig.get("NUCC.EXPAY.SIGNSN"));
                
                NuccExpayCommonMsgbodySysrtninf sysinf = new NuccExpayCommonMsgbodySysrtninf();
                sysinf.setSysRtnCd("00000000");
                sysinf.setSysRtnTm(DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
                body.setSysRtnInf(sysinf);
                res.setMsgHeader(header);
                res.setMsgBody(body);                
                res =(NuccExpayCommonRes) nuccExPayServiceClient.sign(res);
                resMsg = res.getPlainMessage()+res.getSignMessage();
                response.addHeader("HTTP/1.1 200", "OK");
                response.addHeader("Content-Length",String.valueOf(resMsg.length()));
                response.addHeader("Content-type", "application/xml;charset=utf-8");
                response.setContentLength(resMsg.length());
                response.getWriter().write(resMsg);
                response.getWriter().flush();
            }
        } catch (GopayException e) {
            logger.error(e.getMessage());
        } catch (Exception ex){
            logger.error(ex.getMessage());
        }finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    logger.error("notifyBank close error: ", e);
                }
            }
            if (pw != null) {
                try {
                    pw.close();
                } catch (Exception e) {
                    logger.error("notifyBank pw close error: ", e);
                }
                
            }
        }
                
    }
    

    
    
    @Override
    protected ExPayBaseMessage buildMessage(HttpServletRequest request) {
        NuccExpaymentEndRes message = new NuccExpaymentEndRes();
        try {
            String parsexml = this.parseRequst(request);
            message = (NuccExpaymentEndRes) this.paymentToBean(parsexml);
            message.setBank(BankConstants.BANK_LOGO_NUCCPAY);
            message.setBankOrderId(message.getMsgBody().getBizInf().getTrxId());
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return message;
    }

    @Override
    protected OrderInfo buildOrderInfo(HttpServletRequest request, Result result) {
        NuccExpaymentEndRes message = (NuccExpaymentEndRes) result.getModel("res");
       logger.error("NuccExpayServerRes notify:"
               + ToStringBuilder.reflectionToString(message));
       OrderInfo orderInfo = new OrderInfo();
       String amt = message.getAmount().toString();
       if(message.isSuccess() &&  NuccConstants.NUCC_SYSRTNCD_SUCCESS.equals(message.getMsgBody().getSysRtnInf().getSysRtnCd())
                    && (NuccConstants.NUCC_TRXSTATUSCD_SUCCESS.equals(message.getMsgBody().getBizInf().getTrxStatus())
                            || NuccConstants.NUCC_EXCEPTION_SUCCESS.equals(message.getMsgBody().getBizInf().getTrxStatus()))){
           orderInfo.setOrderId(message.getOrderId());// 为了获取系统订单号
           orderInfo.setAmt(amt);
           orderInfo.setNotifyNum("1");
           orderInfo.setPayStatus("00");
           orderInfo.setRetCode("00");
           orderInfo.setRetMsg("");
       }else {
           orderInfo.setOrderId(message.getOrderId());// 为了获取系统订单号
           orderInfo.setAmt(amt);
           orderInfo.setNotifyNum("1");
           orderInfo.setPayStatus("01");
           orderInfo.setRetCode("01");
           orderInfo.setRetMsg("");
       }
       orderInfo.setCardType("");
       orderInfo.setIsNotify(true);
       orderInfo.setBankName("nuccpay");
       return orderInfo;
    }

    @Override
    protected boolean checkParameters(HttpServletRequest request) {
        return true;
    }
    
    /** 
     * 解析
     * @param request
     * @return 
     * @author w_jiqing 
     */
    public String parseRequst(HttpServletRequest request) {
        String body = "";
        try {
            ServletInputStream inputStream = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            while (true) {
                String info = br.readLine();
                if (info == null) {
                    break;
                }
                if (body == null || "".equals(body)) {
                    body = info;
                } else {
                    body += info;
                }
            }
        } catch (UnsupportedEncodingException e) {
            logger.info(e.getMessage());
        } catch (IOException e) {
            logger.info(e.getMessage());
        }
        return body;
    }
    
    /** 
     * 转为对象
     * @param request
     * @return 
     * @author w_jiqing 
     */
    public ExPayBaseMessage cancelToBean(String request) throws GopayException{
        String plainMsg ="";
        String signMsg ="";
        NuccExpayRescindRes message = new NuccExpayRescindRes();
        try{
            int indexPStart = request.indexOf("<root");
            int indexPEnd = request.indexOf("</root>");
            int indexSStart = request.indexOf("{S:");
            int indexSEnd = request.indexOf("}");
            if(indexPStart > -1 && indexPEnd > -1 && indexSStart > -1 && indexSEnd > -1){
                plainMsg = request.substring(indexPStart,indexPEnd+7);
                signMsg = request.substring(indexSStart+3,indexSEnd);
            }else{
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6079);
            }
            message.setPlainMessage(plainMsg);
            message.setSignMessage(signMsg);
            logger.info("解约响应对象：  " + ToStringBuilder.reflectionToString(message));
        }catch(Exception ex){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6079, ex.getMessage()); 
        }
        
        return message;
    }
    
    public ExPayBaseMessage paymentToBean(String request)throws GopayException{
        String plainMsg ="";
        String signMsg ="";
        NuccExpaymentEndRes message = new NuccExpaymentEndRes();
        try{
            int indexP = request.indexOf("</root>");
            int indexS = request.indexOf("{S:");
            if(indexP != -1 && indexS!=-1){
                plainMsg = request.substring(0,indexP+7);
                signMsg = new String(Base64.encodeBase64(request.substring(indexS+3, request.length()-1).getBytes("utf-8")));
            }
           
            XStream xs = new XStream(new DomDriver());
            xs.autodetectAnnotations(true);
            xs.toXML(message);
            message.setPlainMessage(plainMsg);
            message.setSignMessage(signMsg);
            message = (NuccExpaymentEndRes) xs.fromXML(plainMsg);
            logger.info("支付终态通知对象：  " + ToStringBuilder.reflectionToString(message));
        }catch(Exception ex){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6079, ex.getMessage()); 
        }        
        return message;
    }
    
    public ExPayBaseMessage refundToBean(String request) throws GopayException{
        String plainMsg ="";
        String signMsg ="";
        NuccExpayRefundEndRes message = new NuccExpayRefundEndRes();
        try{
            int indexP = request.indexOf("</root>");
            int indexS = request.indexOf("{S:");
            if(indexP != -1 && indexS!=-1){
                plainMsg = request.substring(0,indexP+7);
                signMsg = new String(Base64.encodeBase64(request.substring(indexS+3, request.length()-1).getBytes("utf-8")));
            }
           
            XStream xs = new XStream(new DomDriver());
            xs.autodetectAnnotations(true);
            xs.toXML(message);
            message.setPlainMessage(plainMsg);
            message.setSignMessage(signMsg);
            message = (NuccExpayRefundEndRes) xs.fromXML(plainMsg);
            logger.info("退款终态通知对象：  " + ToStringBuilder.reflectionToString(message));
        }catch(Exception ex){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6079, ex.getMessage()); 
        }        
        return message;
    }

    @Override
    protected boolean checkRefundParameters(HttpServletRequest request) {
        return true;
    }

    @Override
    protected ExPayBaseMessage buildRefundMessage(HttpServletRequest request) {
        NuccExpayRefundEndRes message = new NuccExpayRefundEndRes();
        try {
            String parsexml = this.parseRequst(request);
            message = (NuccExpayRefundEndRes) this.refundToBean(parsexml);
            message.setBank(BankConstants.BANK_LOGO_NUCCPAY);
            message.setBankOrderId(message.getMsgBody().getTrxInf().getTrxId());
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return message;
    }

    @Override
    protected OrderInfo buildRefundOrderInfo(HttpServletRequest request, Result result) {
        NuccExpayRefundEndRes message = (NuccExpayRefundEndRes) result.getModel("res");
        logger.error("NuccRefundServerRes notify:"
                + ToStringBuilder.reflectionToString(message));
        OrderInfo orderInfo = new OrderInfo();
        String amt = message.getAmount().toString();
        if(message.isSuccess() &&  NuccConstants.NUCC_SYSRTNCD_SUCCESS.equals(message.getMsgBody().getSysRtnInf().getSysRtnCd())
                     && (NuccConstants.NUCC_TRXSTATUSCD_SUCCESS.equals(message.getMsgBody().getBizInf().getTrxStatus())
                             || NuccConstants.NUCC_EXCEPTION_SUCCESS.equals(message.getMsgBody().getBizInf().getTrxStatus()))){
            orderInfo.setOrderId(message.getOrderId());// 为了获取系统订单号
            orderInfo.setAmt(amt);
            orderInfo.setNotifyNum("1");
            orderInfo.setPayStatus("00");
            orderInfo.setRetCode("00");
            orderInfo.setRetMsg("");
        }else {
            orderInfo.setOrderId(message.getOrderId());// 为了获取系统订单号
            orderInfo.setAmt(amt);
            orderInfo.setNotifyNum("1");
            orderInfo.setPayStatus("01");
            orderInfo.setRetCode("01");
            orderInfo.setRetMsg("");
        }
        orderInfo.setCardType("");
        orderInfo.setIsNotify(true);
        orderInfo.setBankName("nuccpay");
        return orderInfo;
    }



}
